#ifndef ENGINE_H
#define ENGINE_H

#include "IRenderer.h"
#include "IInput.h"
#include <concrete/Network.h>
#include <concrete/NetworkEvents.h>
#include "InputBinder.h"
#include <concrete/World.h>
#include <utils/Pluginterface.h>
#include <utils/String.h>
#include <utils/Maths.h>
#include <utils/Singleton.h>

class Engine : public Singleton<Engine>
{
    //(Only) allow the singleton to access the constructor
	friend class Singleton<Engine>;
    Engine(/*IGameComponentFactory* componentFactory*/);
    ~Engine();
	
	//Core engine components
    //Note: Could make these components in a map, but no point, as they are so fundamental
    //      Basically, two ways to do it. Can have hard-coded interface objects that will cover any conceivable
    //      requirements, or, can have dynamic component system with onStartOfFrame, onEndOfFrame, etc.
    //      The problem with dynamic component system is type casting. Will have to keep casting retrieved objects
    //      into their known types in order to access specific functionality. Also, could have components only
    //      for gameplay, and not for fundamental game engine components.
	IRenderer*                m_pRenderer;
    //TODO: As noted in Pluginterface.h, consider making these static
	//      (a la singletons) instead of members.
    Pluginterface<IRenderer>  m_RendererPluginterface;
    Multiplayer*              m_pMultiplayer;
    IInput*                   m_pInput;
    Pluginterface<IInput>     m_InputPluginterface;
    //IAudio*                 m_pAudio;
    World*                    m_pWorld;
    //TODO: Consider other components: Event system, logic system etc.
    
    //TODO: Layer objects like these on top of the low-level components above
    InputBinder<ClientEvent>* m_pInputBinder;
    
    bool     m_bRunning;
    unsigned m_iTicksPerSecond;
    
public:
    
    void init(String sTitle, unsigned iWidth, unsigned iHeight, unsigned iBitsPerPixel, bool bFullscreen);
    void start();
    
    IRenderer* getRenderer() { return m_pRenderer; }
    
};

#endif //ENGINE_H
